`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/06/23 22:00:15
// Design Name: 
// Module Name: control
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module control(
    input rst,
    input [6:0] opcode,
    input [2:0] funct3,
    input [6:0] funct7,
    input [1:0] branch_res,
    output reg [1:0] npc_sel,
    output reg rf_we,
    output reg [1:0] wd_sel,
    output reg [2:0] sext_op,
    output reg [2:0] alu_op,
    output reg a_sel,
    output reg b_sel,
    output reg [1:0] branch,
    output reg dram_we,
    output reg [2:0] dram_op
    );
    
    
always @(*)
begin
    if (rst)
    begin
        npc_sel <= 2'bzz;
        rf_we <= 1'bz;
        wd_sel <= 2'bzz;
        sext_op <= 3'bzzz;
        alu_op <= 3'bzzz;
        a_sel <= 1'bz;
        b_sel <= 1'bz;
        branch <= 2'bzz;
        dram_we <= 1'bz;
        dram_op <= 3'bzzz;
    end
    else
    begin
        case (opcode)
            7'b0110011://R
            begin
                npc_sel <= 2'b00;
                rf_we <= 1;
                wd_sel <= 2'b00;
                sext_op <= 3'bxxx;
                a_sel <= 0;
                b_sel <= 0;
                dram_we <= 0;
                dram_op <= 3'bxxx;
                case (funct3)
                    3'b000://add sub
                    begin
                        alu_op <= (funct7 == 7'b0)? `ADD: `SUB;    
                        branch <= 2'bxx;
                    end
                    3'b001://sll
                    begin
                        alu_op <= `LS;    
                        branch <= 2'bxx;
                    end
                    3'b010://slt
                    begin
                        alu_op <= 3'bxxx;    
                        branch <= 2'b01;
                    end
                    3'b011://sltu
                    begin
                        alu_op <= 3'bxxx;    
                        branch <= 2'b10;
                    end
                    3'b100://xor
                    begin
                        alu_op <= `XOR;    
                        branch <= 2'bxx;
                    end
                    3'b101://srl sra
                    begin
                        alu_op <= (funct7 == 7'b0)? `RSL : `RSA;    
                        branch <= 2'bxx;
                    end
                    3'b110:// or
                    begin
                        alu_op <= `OR;    
                        branch <= 2'bxx;
                    end
                    3'b111://and
                    begin
                        alu_op <= `AND;    
                        branch <= 2'bxx;
                    end    
                endcase
            end
            7'b0010011://I
            begin
                npc_sel <= 2'b00;
                rf_we <= 1;
                wd_sel <= 2'b00;
                a_sel <= 0;
                b_sel <= 1;
                dram_we <= 0;
                dram_op <= 3'bxxx;
                case (funct3)
                    3'b000://addi
                    begin
                        alu_op <= `ADD;   
                        sext_op <= `ITYPE; 
                        branch <= 2'bxx;
                    end
                    3'b001://slli
                    begin
                        alu_op <= `LS; 
                        sext_op <= `SHIFT;   
                        branch <= 2'bxx;
                    end
                    3'b010://slti
                    begin
                        alu_op <= 3'bxxx;
                        sext_op <= `ITYPE;    
                        branch <= 2'b01;
                    end
                    3'b011://sltui
                    begin
                        alu_op <= 3'bxxx;
                        sext_op <= `ITYPE;    
                        branch <= 2'b10;
                    end
                    3'b100://xori
                    begin
                        alu_op <= `XOR;
                        sext_op <= `ITYPE;    
                        branch <= 2'bxx;
                    end
                    3'b101://srli srai
                    begin
                        alu_op <= (funct7 == 7'b0)? `RSL : `RSA; 
                        sext_op <= `SHIFT;   
                        branch <= 2'bxx;
                    end
                    3'b110:// ori
                    begin
                        alu_op <= `OR; 
                        sext_op <= `ITYPE;   
                        branch <= 2'bxx;
                    end
                    3'b111://andi
                    begin
                        alu_op <= `AND; 
                        sext_op <= `ITYPE;   
                        branch <= 2'bxx;
                    end
                endcase    
            end
            7'b0000011://I-lode
            begin
                npc_sel <= 2'b00;
                rf_we <= 1;
                wd_sel <= 2'b01;
                alu_op <= `ADD; 
                sext_op <= `ITYPE;    
                a_sel <= 0;
                b_sel <= 1;
                branch <= 2'bxx;
                dram_we <= 0;
                case (funct3)
                    3'b000: dram_op <= `B;
                    3'b100: dram_op <= `BU;
                    3'b001: dram_op <= `HW;
                    3'b101: dram_op <= `HWU;
                    3'b010: dram_op <= `W;
                    default:dram_op <= 3'bxxx;
                endcase
            end
            7'b1100111://jalr
            begin
                npc_sel <= 2'b10;
                rf_we <= 1;
                wd_sel <= 2'b10;
                alu_op <= `ADD; 
                sext_op <= `ITYPE;    
                a_sel <= 0;
                b_sel <= 1;
                branch <= 2'bxx;
                dram_we <= 0;  
                dram_op <= 3'bxxx;  
            end
            7'b0100011://S
            begin
                npc_sel <= 2'b00;
                rf_we <= 0;
                wd_sel <= 2'bxx;
                alu_op <= `ADD; 
                sext_op <= `STYPE;    
                a_sel <= 0;
                b_sel <= 1;
                branch <= 2'bxx;
                dram_we <= 1;   
                case (funct3)
                    3'b000: dram_op <= `B;
                    3'b001: dram_op <= `HW;
                    3'b010: dram_op <= `W;
                    default:dram_op <= 3'bxxx;
                endcase 
            end
            7'b1100011://B
            begin
                case (funct3)
                    3'b000: npc_sel <= (branch_res == `EQ)? 2'b01: 2'b00;
                    3'b001: npc_sel <= (branch_res != `EQ)? 2'b01: 2'b00;
                    3'b100: npc_sel <= (branch_res == `LT)? 2'b01: 2'b00;
                    3'b101: npc_sel <= (branch_res != `LT)? 2'b01: 2'b00;
                    3'b110: npc_sel <= (branch_res == `LT)? 2'b01: 2'b00;
                    3'b111: npc_sel <= (branch_res != `LT)? 2'b01: 2'b00;
                    default: npc_sel <= 2'bzz;
                endcase
                rf_we <= 0;
                wd_sel <= 2'bxx;
                alu_op <= 3'bxxx;
                sext_op <= `BTYPE;    
                a_sel <= 1'bx;
                b_sel <= 1'bx;
                branch <= (funct3 == 3'b110 || funct3 == 3'b111)? 2'b10: 2'b01;
                dram_we <= 0;
                dram_op <= 3'bxxx;
            end
            7'b0110111://lui
            begin
                npc_sel <= 2'b00;
                rf_we <= 1;
                wd_sel <= 2'b11;
                alu_op <= 3'bxxx; 
                sext_op <= `UTYPE;    
                a_sel <= 1'bx;
                b_sel <= 1'bx;
                branch <= 2'bxx;
                dram_we <= 0;
                dram_op <= 3'bxxx;
            end
            7'b0010111://auipc
            begin
                npc_sel <= 2'b00;
                rf_we <= 0;
                wd_sel <= 2'b00;
                alu_op <= `ADD; 
                sext_op <= `UTYPE;    
                a_sel <= 1;
                b_sel <= 1;
                branch <= 2'bxx;
                dram_we <= 0;
                dram_op <= 3'bxxx;
            end
            7'b1101111://J
            begin
                npc_sel <= 2'b01;
                rf_we <= 1;
                wd_sel <= 2'b10;
                alu_op <= 3'bxxx; 
                sext_op <= `JTYPE;    
                a_sel <= 1'bx;
                b_sel <= 1'bx;
                branch <= 2'bxx;
                dram_we <= 0;
                dram_op <= 3'bxxx;
            end
            default:
            begin
                npc_sel <= 2'b00;
                rf_we <= 1'b0;
                wd_sel <= 2'bxx;
                sext_op <= 3'bxxx;
                alu_op <= 3'bxxx;
                a_sel <= 1'bx;
                b_sel <= 1'bx;
                branch <= 2'bxx;
                dram_we <= 1'b0;
                dram_op <= 3'bxxx;
            end
        endcase 
    end
end

endmodule
